﻿using System;
using BuzzX8.Xmpp.StreamElements.Stanza;

namespace BuzzX8.Xmpp.StreamElements.Factories
{
    public class IqFactory : StanzaFactory<IqType, IqStanza, IqModel>
    {
        protected override IqModel CreateModelByParameters(PropertyDictionary parameters)
        {
            return new IqModel(parameters);
        }

        protected override IqStanza CreateNewElement()
        {
            return new IqStanza();
        }

        protected override void UpdateElementByModel(IqStanza element, IqModel model)
        {
            base.UpdateElementByModel(element, model);
            if (model.HasResourceBind) AddBindElement(element, model.ResourceBindInfo);
            if (model.IsRosterOperation) AddRosterOperationElement(element, model.RosterOperationData);
        }

        private void AddBindElement(IqStanza element, ResourceBindInfo resourceBindInfo)
        {
            ResourceBindElement bindInfo = new ResourceBindElement();
            bindInfo.JID = resourceBindInfo.AssignedJid;
            bindInfo.Resource = resourceBindInfo.RequestedResource;
            element.Elements.Add(bindInfo);
        }

        private void AddRosterOperationElement(IqStanza stanza, RosterOperationData operationData)
        {
            IqQueryElement query = new IqQueryElement(XmppNamespaces.Roster);
            AddRosterQueryElements(query, operationData);
            stanza.Elements.Add(query);
            UpdateStanzaTypeForRosterOperation(stanza, operationData.OperationType);
        }

        private void AddRosterQueryElements(IqQueryElement query, RosterOperationData queryInfo)
        {
            switch (queryInfo.OperationType)
            {
                case RosterOperationType.GetItems:
                    break;

                case RosterOperationType.AddItem:
                case RosterOperationType.PushItem:
                case RosterOperationType.UpdateItem:
                    query.AddElement(queryInfo.Item);
                    break;

                case RosterOperationType.ItemsResponse:
                    AddRosterResultElements(query, queryInfo);
                    break;

                case RosterOperationType.DeleteItem:
                    queryInfo.Item.Subscription = SubscriptionStatus.Remove;
                    query.AddElement(queryInfo.Item);
                    break;

                default:
                    throw new NotImplementedException();
            }
        }

        private void AddRosterResultElements(IqQueryElement iqQuery, RosterOperationData rosterQueryInfo)
        {
            foreach (RosterItem rosterItem in rosterQueryInfo.ResponseItems) iqQuery.AddElement(rosterItem);
        }

        private void UpdateStanzaTypeForRosterOperation(IqStanza stanza, RosterOperationType operationType)
        {
            switch (operationType)
            {
                case RosterOperationType.GetItems:
                    stanza.Type = IqType.Get;
                    break;

                case RosterOperationType.ItemsResponse:
                case RosterOperationType.PushItem:
                    stanza.Type = IqType.Result;
                    break;

                case RosterOperationType.AddItem:
                case RosterOperationType.UpdateItem:
                case RosterOperationType.DeleteItem:
                    stanza.Type = IqType.Set;
                    break;

                default:
                    throw new NotImplementedException();
            }
        }
    }
}
